package token

import (
	"encoding/json"
	"time"

	"gitee.com/liuxiaowei123/vblog-01/vblog-01/vblog/exception"
	"gitee.com/liuxiaowei123/vblog-01/vblog-01/vblog/user"
	"github.com/rs/xid"
)

func NewToken() *Token {
	return &Token{
		// 生产一个UUID的字符串
		AccessToken:           xid.New().String(),
		AccessTokenExpiredAt:  7200,
		RefreshToken:          xid.New().String(),
		RefreshTokenExpiredAt: 3600 * 24 * 7,
		CreatedAt:             time.Now().Unix(),
	}
}

type Token struct {
	// 该Token是颁发给哪个用户的
	UserId int `json:"user_id"`
	// 人的名称， user_name
	UserName string `json:"username" gorm:"column:username"`
	// 颁发给用户的访问令牌(用户需要携带Token来访问接口)
	AccessToken string `json:"access_token"`
	// 过期时间(2h), 单位是秒
	AccessTokenExpiredAt int `json:"access_token_expired_at"`
	// 刷新Token
	RefreshToken string `json:"refresh_token"`
	// 刷新Token过期时间(7d)
	RefreshTokenExpiredAt int `json:"refresh_token_expired_at"`
	// 创建时间
	CreatedAt int64 `json:"created_at"`
	// 更新实现
	UpdatedAt int64 `json:"updated_at"`
	// 额外补充信息, gorm忽略处理，也就是无需入库；只要返回的token中有此字段就可以
	Role user.Role `gorm:"-"`
}

func (t *Token) String() string {
	js, _ := json.Marshal(t)
	return string(js)
}

// 应该不用实现此方法，按约定就可自动实现
func (t *Token) TableName() string {
	return "tokens"
}

// 定义token过期时间
func (t *Token) ExpiredTime() time.Time {
	/* time.Unix(t.CreatedAt, 0)：将Token结构体中的CreatedAt字段转化为一个time.Time类型的值
	这里的0表示纳秒级的偏移量，因此此函数将精确到秒*/
	return time.Unix(t.CreatedAt, 0).
		/* 为了对t.AccessTokenExpiredAt进行操作（比如乘以 time.Second），需要将其转换为 time.Duration 类型
		这是因为只有 time.Duration 类型的值才能直接进行算术运算
		*/
		Add(time.Duration(t.AccessTokenExpiredAt) * time.Second)
	// 错误写法 Add(time.Duration(t.AccessTokenExpiredAt * time.Second) )
}

// 定义token是否过期
func (t *Token) IsExpired() error {
	// 当前时间-过期时间
	duration := time.Since(t.ExpiredTime())

	expiredSeconds := duration.Seconds()
	if expiredSeconds > 0 {
		return exception.NewTokenExpired("token %s 过期了 %f秒",
			t.AccessToken, expiredSeconds)
	}
	return nil
}
